﻿using System;
using Autofac.Extensions.DependencyInjection;
using IdentityServer4.AccessTokenValidation;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.IdentityModel.Tokens;
using OpenAuth.App;
using OpenAuth.Mvc.Models;
using OpenAuth.Repository;

namespace OpenAuth.Mvc
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }
        //配置文件读取，依赖注入构造函数注入
        public IConfiguration Configuration { get; }

        // 此方法由运行时调用。使用这种方法将服务添加到容器中,用于注册服务
        public IServiceProvider ConfigureServices(IServiceCollection services)
        {
            #region 最简单的依赖注入实现
            //core原生设置依赖注入
            //services.AddTransient<Iuser, UserManage>();
            ////注册MVC所需要的相关服务到IoC容器里
            //services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
            #endregion



            var identityServer = ((ConfigurationSection)Configuration.GetSection("AppSetting:IdentityServerUrl")).Value;
            if (!string.IsNullOrEmpty(identityServer))
            {
                System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();

                services.AddAuthentication(options =>
                {
                    options.DefaultScheme = "Cookies";
                    options.DefaultChallengeScheme = "oidc";
                })
                    .AddCookie("Cookies")
                    .AddOpenIdConnect("oidc", options =>
                    {
                        options.Authority = identityServer;
                        options.RequireHttpsMetadata = false;

                        options.ClientId = "OpenAuth.Mvc";
                        options.SaveTokens = true;
                        options.TokenValidationParameters = new TokenValidationParameters
                        {
                            NameClaimType = "name",
                            RoleClaimType = "role",
                        };
                    });
            }
            
            services.Configure<CookiePolicyOptions>(options =>
            {
                // This lambda determines whether user consent for non-essential cookies is needed for a given request.
                //关闭GDPR规范
                options.CheckConsentNeeded = context => false;
                options.MinimumSameSitePolicy = SameSiteMode.None;
            });


            services.AddMvc(option =>
            {
                option.Filters.Add<OpenAuthFilter>();
                option.ModelBinderProviders.Insert(0, new JsonBinderProvider());
            }).SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
            services.AddMemoryCache();
            services.AddOptions();
            //路由地址全部变成小写
            services.AddRouting(options => options.LowercaseUrls = false);

            //映射配置文件
            services.Configure<AppSetting>(Configuration.GetSection("AppSetting"));

            //在startup里面只能通过这种方式获取到appsettings里面的值，不能用IOptions😰
            var dbType = ((ConfigurationSection)Configuration.GetSection("AppSetting:DbType")).Value;
            if (dbType == Define.DBTYPE_SQLSERVER)
            {
                
                services.AddDbContext<OpenAuthDBContext>(options =>
                    options.UseSqlServer(Configuration.GetConnectionString("OpenAuthDBContext")));
                services.AddDbContext<ApiDBContext>(options => options.UseSqlServer(Configuration.GetConnectionString("ApiDBContext")));

            }
            else  //mysql
            {
                services.AddDbContext<OpenAuthDBContext>(options =>
                    options.UseMySql(Configuration.GetConnectionString("OpenAuthDBContext")));
            }

            services.AddHttpClient();
            //使用AutoFac进行注入
            return new AutofacServiceProvider(AutofacExt.InitAutofac(services));

            #region 依赖注入的生命周期
            //1、Transient每次调用都是不同的实例 Microsoft.Extensions.Options.IConfigureOptions<T>；
            //2、Scoped每次请求是同一个实例，如 Entity Framework contexts；
            //3、Singleton只有一个实例，如Microsoft.Extensions.Logging.ILogger<T>；
            //具体使用哪种，要根据具体情况而定；

            //1、比如我们一般的业务逻辑都是Transient，这个也是比较常用的；意味着只会创建一个实例，该实例在需要它的所有组件之间共享。因此始终使用相同的实例

            //2、Scoped相对用的比较少，当然也有很多业务逻辑也有用Scoped的；当然他的妙用肯定是每次请求一个实例，比如我们在系统中获取登录系统用户的Id，这时就可以用Scoped，不管在Service层或者Repository层等等，获取的都是同一个用户；意味着每个作用域创建一个实例。作用域是在对应用程序的每个请求上创建的，因此，任何注册为Scoped的组件每个请求都会创建一次。

            //3、Singleton很多都是系统级别设计用单利，比如日志；该实例在需要它的所有组件之间共享。因此始终使用相同的实例。


            #endregion
        }


        //这里扩展得东西，是针对所有请求得，而不是针对某一个功能
        /// <summary>
        /// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        /// </summary>
        /// <param name="app">应用程序建造者-Build（）-应用程序得实例--请求就是靠他处理--用中间件组装得一个appcaion处理流程</param>
        /// <param name="env"></param>
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
          

            app.UseAuthentication();
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Error");
            }

            app.UseStaticFiles();

            app.UseCookiePolicy();

      


            #region 默认路由（实际上实现了一个中间件）
            //app.UseMvc(routes =>
            //{
            //    routes.MapRoute(
            //        name: "Default",
            //        template: "{controller}/{action}/{id?}",
            //        defaults: new { controller = "Home", action = "Index" }
            //    );
            //});
            app.UseMvcWithDefaultRoute();
            #endregion


        }
    }
}


   